<?php
/**
 * the base item model
 */
class DigCms_Model_Item extends Dig_Model_Abstract {
    public $id;
    public $name;
    public $namespace;
    public $position;
    public $publish_level;
    public $parent_id = 0;
    public $date_created;
    public $created_by;
    public $date_updated;
    public $updated_by;
    public $admin_notes;
    public $navigation_item = 1;
    protected $_namespace;
    protected $_defaultChild = null;
    const DEFAULT_NAMESPACE = 'DigCms_Model_Item';

    /**
     * loads the model data
     *
     * @param mixed $page
     */
    public function __construct ($page = null) {
        if(!is_array($this->_defaultChild)) {
            $defaultType = DigCms_Service_Item::getDefaultType();
            $this->_defaultChild = array(
                'model' => $defaultType['namespace'],
                'name'  => 'Item'
            );
        }
        $this->_namespace = $this->_getNamespace();
        if(is_array($page)) {
            $this->loadArray($page);
        } elseif (null != $page) {
            $this->_loadPageObject($page);
        }
    }

    /**
     * determines if the item is an instance of this base model class
     *
     * @return boolean
     */
    public function isBaseItem() {
        if(get_class($this) == 'DigCms_Model_Item') {
            return true;
        }
    }

    /**
     * enables you to load an item instance after it has been constructed
     *
     * @param int $id
     */
    public function load($id) {
        if($id > 0) {
            $this->_loadPageObject($id);
        }
    }

    /**
     * determines if the item is a navigation item
     *
     * @return boolean
     */
    public function isNavigationItem() {
        return $this->navigation_item == 1;
    }

    /**
     * returns the default child for the item
     *
     * @return array
     */
    public function getDefaultChild() {
        return $this->_defaultChild;
    }

    /**
     * this method enables you to pass an array of keys to an item and find
     * the first key that is set
     *
     * this is commonly used with default content; for example the menu label
     * may default to the page title
     *
     * @param DigCms_Model_Item $item
     * @param array $keys
     * @return string
     */
    public function overloadContent($keys) {
        foreach ($keys as $key) {
            if(! empty($this->$key)) {
                return $this->$key;
            }
        }
        return false;
    }

    /**
     * this method enables content items to inherit content from their parents
     *
     * @param string $key
     */
    public function inheritContent($key) {
        if(isset($this->$key)) {
            return $this->$key;
        }
        $parents = $this->parents();
        if(is_array($parents) && count($parents) > 0) {
            foreach ($parents as $parent) {
                if(isset($parent->$key)) {
                    return $parent->$key;
                }
            }
        }
        return false;
    }

    /**
     * adds a child to the current item and then returns the child
     *
     * @return DigCms_Model_Item
     */
    public function appendChild() {
        $defaultChild = $this->getDefaultChild();
        $model = $defaultChild['model'];
        $item = new $model();
        $item->name = $defaultChild['name'];
        $item->namespace = $defaultChild['model'];
        $item->parent_id = $this->id;
        $item->save();
        return $item;
    }
    
    /**
     * creates a new model instance from a row or primary key (id)
     *
     * @param mixed $row
     * @return DigCms_Model_Item
     */
    public static function factory($row, $cacheEnabled = true) {
        if(is_array($row)) {
            $id = $row['id'];
            $namespace = $row['namespace'];
        } elseif (is_object($row)) {
            $id = $row->id;
            $namespace = $row->namespace;
        } elseif (intval($row) > 0) {
            $id = intval($row);
        } else {
            return false;
        }

        if($cacheEnabled) {
            $item = self::fetchItemFromCache($id);
            if($item instanceof DigCms_Model_Item) {
                return $item;
            }
        }
        if(!is_object($row) && !is_array($row)) {
            $model = Dig_Service_Factory::model('items');
            $row = $model->find($id)->current();
            $namespace = $row->namespace;
        }

        if(empty($namespace)) {
            // fetch the default item type
            $defaultType = DigCms_Service_Item::getDefaultType();
            $namespace = $defaultType['module'] . '_Model_' . $defaultType['controller'];
        }
        
        $classname = ucfirst($namespace);
        // the namespaces map directly to the model class name
        return new $classname($row);
    }

    /**
     * returns the items underlying model
     *
     * @return Zend_Db_Table
     */
    public function model() {
        return Dig_Service_Factory::model('items');
    }

    /**
     * this method returns the db select object with the namespace set
     * it does not add the namespace filter for base items
     * from the base item model your select will return all types
     *
     * @param bool $filterNamespace
     */
    public function select ($filterNamespace = true) {
        $select = $this->model()->select();
        if($filterNamespace && !$this->isBaseItem()) {
            $select->where('namespace = ?', $this->_namespace);
        }
        return $select;
    }

    /**
     * finds an item by its name
     *
     * @param string $name
     * @param int $parentId
     * @return DigCms_Model_Item
     */
    public static function getNodeByName($name, $parentId = 0) {
        //Zend_Debug::dump($name);die();
        $model = Dig_Service_Factory::model('items');
        $select = $model->select();
        $select->where('name = ?', $name);
        $select->where('parent_id = ?', $parentId);
        $row = $model->fetchRow($select);
        if($row) {
            return self::factory($row);
        }
        return false;
    }


    /**
     * finds the specified item by searching the attributes
     *
     * see the _joinSelectToNodes method for more details about the filters
     * and select
     *
     * @param array $filters
     * @param Zend_Db_Table_Select $select
     * @return array
     *
     */
    public function fetchItemsByAttributes($filters = array(),
            Zend_Db_Table_Select $select = null) {
        return $this->fetchAll( $this->_joinSelectToNodes($filters, $select));
    }

    /**
     *
     * operates on the same principal as the fetchItemsByAttributes
     * but only returns a single item
     *
     * see the _joinSelectToNodes method for more details about the filters
     * and select
     *
     * @param array $filters
     * @param Zend_Db_Table_Select $select
     * @return DigCms_Model_Item
     */
    public function findItemByAttributes($filters = array(),
            Zend_Db_Table_Select $select = null) {
        return $this->fetchRow( $this->_joinSelectToNodes($filters, $select));
    }

    /**
     * binds the items table select object to the item_nodes table
     *
     * you pass the filters as an array
     * each item in the array is added to the where clause of the join
     * for example
     * $filters = array(
     *      'content'   => 'LIKE "%digitalus%"',
     *      'image'     => 'IS NOT NULL'
     * );
     *
     * You can optionally pass a select object, which enables you to add
     * additional conditions to the base items table
     *
     * IMPORTANT: these filters are not escaped using the quoteInto() method
     * you should do that while you create the filters
     * this is done to keep the filters simple and may be refactored
     *
     *   todo refactor how the filters are escaped
     *
     *   todo    I want to refactor the select join method. i think it would
     * be much more intuitive to be able to create a select object for the
     * sub table and pass this as the argument to the join rather than
     * manually dealing with the aliases
     *
     * @param array $filters
     * @param Zend_Db_Table_Select $select
     * @return Zend_Db_Table_Select
     */
    protected function _joinSelectToNodes($filters = array(),
            Zend_Db_Table_Select $select = null) {
        if($select == null) {
            $select = $this->model()->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
        }
        $select->setIntegrityCheck ( false );
        $select->distinct();
        $select->join('item_nodes', 'items.id = item_nodes.item_id', null);

        foreach($filters as $node => $whereClause) {
            $select->where('item_nodes.node = ? AND item_nodes.content ' . $whereClause, $node);
        }
        //die($select->__toString());
        return $select;
    }

    /**
     * the fetchRow method wraps the Zend_Db_Table fetchRow method
     *
     * it returns the row as an instance of the appropriate model
     *
     * @param Zend_Db_Select
     * @return DigCms_Model_Item
     */
    public function fetchRow (Zend_Db_Select $select = null) {
        if (null == $select) {
            $select = $this->select();
        }
        $row = $this->model()->fetchRow($select);
        if ($row) {
            return self::factory($row);
        }
        return false;
    }
    /**
     * the fetchAll method wraps the Zend_Db_Table fetchAll method
     * but returns an array of new instances of Digitalus_Model
     *
     * @param Zend_Db_Select
     * @return array
     */
    public function fetchAll (Zend_Db_Select $select = null) {
        if (null == $select) {
            $select = $this->select();
        }
        $result = $this->model()->fetchAll($select);

        if ($result->count() > 0) {
            foreach ($result as $row) {
                $model = self::factory($row);
                $resultSet[] = $model;
            }
            return $resultSet;
        }
    }

    /**
     * this method works like the jQuery closest method.
     *
     * It returns the closest parent that matches the namespace
     * 
     * @param string $namespace
     */
    public function closest($namespace) {
        $parentId = $this->parent_id;
        while($parentId) {
            $parent = self::factory($parentId);
            if($parent) {
                $parentId = $parent->parent_id;
                if($parent->namespace == $namespace) {
                    return $parent;
                }
            } else {
                $parentId = false;
            }
        };
    }

    /**
     *  todo: figure out a better naming convention with the item model methods
     */
    public function getParent() {
        return self::factory($this->parent_id);
    }

    /**
     * fetches the parents of the current item
     *
     * @param mixed $item
     * @param array $parents
     * @return array
     */
    public function parents( $item = null, $parents = array()) {
        if($item == null) {
            $item = $this;
        }
        $cachedParents = self::fetchRelatedItemsFromCache($item->id, 'parent');
        if($cachedParents) {
            return $cachedParents;
        }

        $parentItem = self::factory($item->parent_id);

        if(!$parentItem) {
            self::saveRelatedItemsToCache($item->id, $parents, 'parent');
            return $parents;
        }
        $parents[] = $parentItem;
        if($parentItem && $parentItem->parent_id > 0) {
            $parents = $this->parents($parentItem, $parents);

        }
        self::saveRelatedItemsToCache($item->id, $parents, 'parent');
        return $parents;
    }

    /**
     * returns the previous sibling, ordered by position
     */
    public function previous($namespace = null) {
        $select = $this->select($namespace);
        if($this->position == 0) {
            $select = $this->select($namespace);
            $select->where('parent_id = ?', $this->parent_id);
            $select->where('id != ?', $this->id);
            $select->order('position DESC');
            $row = $this->fetchRow($select);
        } else {
            $select->where('parent_id = ?', $this->parent_id);
            $select->where('position < ?', $this->position);
            $select->order('position');
            $row = $this->fetchRow($select);
        }
        return $row;
    }

    /**
     * returns the next sibling, ordered by position
     */
    public function next($namespace = null) {
        $select = $this->select($namespace);
        $select->where('parent_id = ?', $this->parent_id);
        $select->where('position > ?', $this->position);
        $select->order('position');
        $row = $this->fetchRow($select);
        if(! $row) {
            $select = $this->select($namespace);
            $select->where('parent_id = ?', $this->parent_id);
            $select->where('id != ?', $this->id);
            $select->order('position');
            $row = $this->fetchRow($select);
        }
        return $row;
    }

    /**
     * Returns the children of the current item
     * if the type is set then it will only return the items of the specified type
     *
     * @param string $type
     * @param int $parentId
     */
    public function children($type = null, $parentId = null) {
        if($parentId == null) {
            $parentId = (isset($this->id)) ? $this->id : 0;
        }
        $relation = 'children';
        $select = $this->select(false);
        if($type != null) {
            $select->where('namespace = ?', $type);
            $relation .= '_of_type_' . $type;
        }
        
        // caching these is not implemented
        $children = self::fetchRelatedItemsFromCache($parentId, $relation);
        if($children) {
            return $children;
        }
        
        $select->where('parent_id = ?', $parentId);
        $select->order('position');
        //Zend_Debug::dump($select->__toString());
        $children = $this->fetchAll($select);
        self::saveRelatedItemsToCache($parentId, $children, $relation);
        return $children;
    }
        /**
     * this method is similar to the children method, but returns a collection of all of the descendents.
     * use with care since this is an expensive recursive operation
     *
     * @param string $type
     */
    public function descendents($type = null) {
        set_time_limit(0);
        $descendents = array();
        $select = $this->select(false);
        $select->where('parent_id = ?', $this->id);
        $children = $this->fetchAll($select);
        if($children) {
            foreach ($children as $child) {
                $grandchildren = $child->descendents($type);
                if($grandchildren) {
                    foreach ($grandchildren as $grandchild) {
                        if(($type != null && $grandchild->namespace == $type) || $type == null) {
                            $descendents[] = $grandchild;
                        }
                    }
                }
                if(($type != null && $child->namespace == $type) || $type == null) {
                    $descendents[] = $child;
                }
            }
        }
        return $descendents;
    }

    /**
     * determines if the current item has any children
     */
    public function hasChildren() {
        $select = $this->select(false);
        $select->where('parent_id = ?', $this->id);
        if($this->fetchRow($select)) {
            return true;
        }
    }

    /**
     * adds an item to the current item
     *
     * @param DigCms_Model_Item $child
     */
    public function addChild($child) {
        $child->parent_id = $this->id;
        $child->save();
    }

    /**
     * returns an array of the public properties of the model
     *
     * @return array
     */
    public function toArray () {
        $properties = $this->properties();
        foreach ($properties as $property) {
            $array[$property] = $this->$property;
        }
        return $array;
    }

    /**
     * the loadArray method loads the model with an array of data
     * it does not support overloading, so you can only load
     * defined public properties
     *
     * @param array $data
     */
    public function loadArray ($data = array()) {
        //Zend_Debug::dump($data);
        $propertyArray = $this->properties();
        // these are the static fields
        if (isset($data['id'])) {
            $this->id = $data['id'];
            unset($data['id']);
        }
        foreach ($data as $key => $value) {
            if (in_array($key, $propertyArray)) {
                $this->$key = $value;
            }
        }
    }

    /**
     * renames an item
     * 
     * @param string $newName
     */
    public function rename($newName) {
        $this->name = $newName;
        $this->save();
    }

    /**
     * saves the current item
     *
     */
    public function save ($data = null) {
        if($data != null) {
            $this->loadArray($data);
        }
        if (isset($this->id)) {
            $parentId = intval($this->parent_id);
            self::removeItemFromCache($this->id);
            $this->_update();
            if($this->parent_id != $parentId) {
                // TODO refactor clearing the cache after you move an item
                self::removeAllRelatedItemsFromCache();
            }
            self::saveItemToCache($this);
        } else {
            $this->_insert();
            self::saveItemToCache($this);
            // TODO refactor clearing the cache after you move an item
            self::removeAllRelatedItemsFromCache();
        }
    }
    /**
     * this method finds the parent of an item based on the reference and rel that jsTree sends
     * 
     * @param integer $referenceId
     * @param string $rel
     * @return DigCms_Model_Item
     */
    public static function getParentByReference ($referenceId, $rel) {
        $referenceItem = self::factory($referenceId);

        if(!$referenceItem) {
            return false;
        }

        switch ($rel) {
            case 'before':
            case 'after':
                return self::factory($referenceItem->parent_id);
            case 'inside' :
                return $referenceItem;
        }
    }
    /**
     * moves the specified item to a new position
     *
     * @param int $itemId, the item to move
     * @param int $referenceId, the id of the item which the item will be moved in relation to
     * @param string $rel, the direction to move it (before, after, inside)
     */
    public function move ($referenceId, $rel) {
        // TODO refactor clearing the cache after you move an item
        //self::removeAllRelatedItemsFromCache();
        $referenceItem = $this->model()->find($referenceId)->current();
        
        if(!$referenceItem) {
            return false;
        }

        switch ($rel) {
            case 'before' :
                $parent = $referenceItem->parent_id;
                $position = $referenceItem->position;
                break;
            case 'after' :
                $parent = $referenceItem->parent_id;
                $position = $referenceItem->position + 1;
                break;
            case 'inside' :
                $parent = $referenceItem->id;
                $position = 0;
                break;
        }

        //echo $parent . PHP_EOL . $position . PHP_EOL;
        $this->_moveToPosition($parent, $position);
    }

    /**
     * this method moves and item and normalizes its siblings
     *
     * @param int $position
     * @param int $parentId
     */
    protected function _moveToPosition($parent, $position) {
        if($position == null) {
            $position = 0;
        } else {
            $position = intval($position);
        }
        $this->position = $position;
        $this->parent_id = $parent;
        $select = $this->model()->select();
        $select->where('parent_id = ?', $this->parent_id);
        $select->where('`position` >= ?', $position);
        $select->order('position');
        $siblingsToMove = $this->model()->fetchAll($select);
        if($siblingsToMove) {
            foreach($siblingsToMove as $sibling) {
                $position++;
                //Zend_Debug::dump($position, $sibling->id);
                $sibling->position = $position;
                $sibling->save();
            }
        }

        self::removeItemFromCache($this->id);
        $this->save();
    }

    /**
     * returns the next position to place the new child in
     */
    public function nextPosition() {
        $select = $this->select(false);
        $select->where('parent_id = ?', $this->id);
        $select->order('position DESC');
        $lastChild = $this->model()->fetchRow($select);
        if($lastChild) {
            return $lastChild->position + 1;
        } else {
            return 0;
        }

    }

    /**
     * this loads the model class with the page content and properties
     *
     * @param mixed $page
     */
    protected  function _loadPageObject ($page) {
        if (is_object($page) && $page instanceof Zend_Db_Table_Row) {
            $row = $page;
            $this->id = $row->id;
        } else {
            $this->id = intval($page);
            $row = $this->_getInnerRow();
        }
        if ($row) {
            // TODO refactor the name generation and move it to a function
            $namespace = (!empty($row->namespace)) ? $row->namespace : self::DEFAULT_NAMESPACE;
            if (!empty($namespace) && 
                    $namespace != $this->_getNamespace() &&
                    $namespace != self::DEFAULT_NAMESPACE) {
                throw new Zend_Exception('Unable to cast page type:' . $namespace . ' to type:' . $this->_getNamespace());
            }
            $this->name = $row->name;
            $this->parent_id = $row->parent_id;
            $this->namespace = $row->namespace;
            $this->position = $row->position;
            $this->publish_level = $row->publish_level;
            $this->date_created = $row->date_created;
            $this->date_updated = $row->date_updated;
            $this->created_by = $row->created_by;
            $this->updated_by = $row->updated_by;
            $this->navigation_item = $row->navigation_item;
            // TODO refactor how the page model loads the items. it should be more dynamic!

            $nodes = DigCms_Model_ItemNode::getNodes($this->id);
            if ($nodes) {
                $properties = $this->properties();
                foreach ($properties as $property) {
                    if(! $this->_isBaseColumn($property) && isset($nodes[$property])) {
                        $this->$property = $nodes[$property];
                        $value = null;
                    }
                }
            }
        } else {
            throw new Zend_Exception("Unable to load content item");
        }
        self::saveItemToCache($this);
        //Zend_Debug::dump($this->updated_by);
    }

    /**
     * determines the namespace based on the name of the model
     * 
     * @return string
     */
    protected function _getNamespace() {
        return get_class($this);
    }

    /**
     * fetches the related Zend_Db_Table_Row
     *
     * @param int $id
     * @return Zend_Db_Table_Row
     */
    protected function _getInnerRow ($id = null) {
        if ($id == null) {
            $id = $this->id;
        }
        return $this->model()->find($id)->current();
    }
    /**
     * returns the public properties of the item as an array
     * 
     * @return array
     */
    public function properties () {
        $propertyArray = array();
        $class = new Zend_Reflection_Class($this);
        $properties = $class->getProperties();
        foreach ($properties as $property) {
            if ($property->isPublic()) {
                $propertyArray[] = $property->getName();
            }
        }
        return $propertyArray;
    }
    /**
     * determines if the column you passed is in the base items table
     * 
     * @param string $column
     */
    protected function _isBaseColumn($column) {
        return in_array($column, $this->model()->info('cols'));
    }

    /**
     * inserts a new item into the database
     */
    protected function _insert () {
        //create the new item
        $row = $this->model()->createRow();
        $row->date_created = time();
        $row->created_by = DigUser_Service_User::current()->id;
        $row->save();
        // now fetch the id of the row you just created and return it
        $id = $this->model()->getAdapter()->lastInsertId();
        $this->id = $id;
        $this->_update();
    }

    /**
     * updates an existing item in the database
     */
    protected function _update () {
        $data = $this->toArray();
        $id = $this->id;
        // find the page
        $row = $this->model()->find($id)->current();
        if ($row) {
            $name = strtolower($data['name']);
            $name = str_replace(' ', '_', trim($name));
            $name = str_replace('-', '_', $name);
            $row->name = $name;
            $row->parent_id = $data['parent_id'];
            $row->date_updated = time();
            $row->publish_level = $data['publish_level'];

            if(!empty ($data['namespace'])) {
                $row->namespace = $data['namespace'];
            } elseif($this->_getNamespace() != self::DEFAULT_NAMESPACE) {
                $row->namespace = $this->_getNamespace();
            }

            $row->navigation_item = $data['navigation_item'];
            $row->position = $data['position'];
            
            $row->updated_by = DigUser_Service_User::current()->id;
            $row->save();
            // unset each of the fields that are set in the pages table
            unset($data['id']);
            unset($data['name']);
            unset($data['parent_id']);
            unset($data['publish_level']);
            unset($data['namespace']);
            // set each of the other fields in the content nodes table
            if (count($data) > 0) {
                foreach ($data as $key => $value) {
                    DigCms_Model_ItemNode::setNode($id, $key, $value);
                }
            }
        } else {
            throw new Zend_Exception('Could not open page to update!');
        }
    }
    /**
     * deletes an item
     *
     * @param int $id
     */
    public function delete ($id = null) {
        if($id == null) {
            $id = $this->id;
        }
        if ($id != null) {
            self::removeItemFromCache($id);
            $this->model()->delete('id = ' . $id);
            DigCms_Model_ItemNode::removeNodes($id);
        } else {
            throw new Zend_Exception('Unable to delete item; the item is empty!');
        }
    }

    /**
     * these methods handle the item caching
     *
     * it saves them internally as an array so it does not have to cache the
     * Zend_Db_Table object for each item
     *
     */

    public static function saveItemToCache(DigCms_Model_Item $item) {
        $cache = Dig_Service_Core::getInstance()->getCache();
        $cacheKey = 'item_' . $item->id;
        return $cache->save($item->toArray(), $cacheKey);
    }

    /**
     * this method attempts to find the selected item in the cache
     * and then loads the array into a new item object
     *
     * @param mixed $row
     */
    public static function fetchItemFromCache($itemId) {
        $cache = Dig_Service_Core::getInstance()->getCache();
        $cacheKey = 'item_' . $itemId;
        $itemArray = $cache->load($cacheKey);
        if($itemArray) {
            return self::factory($itemArray, false);
        }
    }

    /**
     * this method removes the selected item from the cache, by both id
     * and tag. this clears all instances, including where the item is
     * a parent, sibling, or child
     *
     * @param int $itemId
     */
    public static function removeItemFromCache($itemId) {
        $cache = Dig_Service_Core::getInstance()->getCache();
        $cacheKey = 'item_' . $itemId;
        // first remove the item
        $cache->remove($cacheKey);
        // then remove all tagged cache files
        $cache->clean(
            Zend_Cache::CLEANING_MODE_MATCHING_TAG,
            array($cacheKey)
        );
    }

    /**
     * NOT IMPLEMENTED
     *
     */
    public static function saveRelatedItemsToCache($itemId, $relatedItems, $relation) {
        return false;
        if(is_array($relatedItems) && count($relatedItems) > 0) {
            $cacheKey = 'item_' . $itemId . '_' . $relation;
            $tagArray[] = 'related_items';
            $tagArray[] = 'item_' . $itemId;
            $tagArray[] = 'item_' . $relation; // add this so you can purge all of the parents
            foreach ($relatedItems as $item) {
                // store the item as
                $itemArray[] = $item->toArray();
                $tagArray[] = 'item_' . $item->id;
            }
            $cache = Dig_Service_Core::getInstance()->getCache();
            $cache->save($itemArray, $cacheKey, $tagArray);
        }
    }

    /**
     * NOT IMPLEMENTED
     *
     */
    public static function fetchRelatedItemsFromCache($itemId, $relation) {
        return false;
        $cacheKey = 'item_' . $itemId . '_' . $relation;
        $cache = Dig_Service_Core::getInstance()->getCache();
        $relatedItems = $cache->load($cacheKey);
        Zend_Debug::dump($cacheKey);
        if(is_array($relatedItems) && count($relatedItems) > 0)  {
            foreach ($relatedItems as $item) {
                $itemArray[] = self::factory($item);
            }
            return $itemArray;
        }
        return false;
    }
   /**
     * NOT IMPLEMENTED
     *
     */
    public static function removeRelatedItemsFromCache($itemId, $relation) {
        return false;
        $cacheKey = 'item_' . $itemId . '_' . $relation;
        $cache = Dig_Service_Core::getInstance()->getCache();
        $cache->remove($cacheKey);
    }

    /**
     * NOT IMPLEMENTED
     *
     */
    public static function removeAllRelatedItemsFromCache()
    {
        return false;
        $cache = Dig_Service_Core::getInstance()->getCache();
        $cache->clean(
            Zend_Cache::CLEANING_MODE_MATCHING_TAG,
            array('related_items')
        );
    }
}
?>